class Persona < ActiveRecord::Base

  acts_as_taggable

  scope_out :alumnos, :conditions=>"coeficiente_id=#{Coeficiente::ALUMNO}"
  scope_out :alumnos_preyoga, :conditions=>"coeficiente_id=#{Coeficiente::ALUMNO} and grado_id=#{Grado::ASPIRANTE}"
  scope_out :alumnos_yoga, :conditions=>"coeficiente_id=#{Coeficiente::ALUMNO} and grado_id>#{Grado::ASPIRANTE}"
  scope_out :ex_alumnos, :conditions=>"coeficiente_id=#{Coeficiente::EXALUMNO}"
  scope_out :prospects, :conditions=>"coeficiente_id>#{Coeficiente::FP} AND coeficiente_id<#{Coeficiente::ALUMNO}"
  scope_out :fps, :conditions=>"coeficiente_id=#{Coeficiente::FP}"
  scope_out :not_alumnos, :conditions=>"coeficiente_id<>#{Coeficiente::ALUMNO}"

  file_column :foto
  
  # dependent hace que sea ON DELETE CASCADE
  has_many :visitas, :dependent=>:destroy
  
  has_many :plans, :class_name => 'Plan', :foreign_key=>'alumno_id', :dependent=>:destroy
  has_many :tickets, :class_name=>'Ticket', :through=>:plans, :source=>:tickets
  
  has_many :gestions, :class_name => 'Gestion', :dependent=>:destroy
  has_many :reunions, :class_name => 'Reunion', :dependent=>:destroy
  has_many :revisacions, :class_name => 'Revisacion', :dependent=>:destroy
  
  # clases de prueba
  has_many :pruebas, :dependent=>:destroy

  #una misma persona podria entrar y salir mas de una vez a la unidad
  has_many :matriculas, :dependent=>:destroy
  has_many :evasions, :dependent=>:destroy

  belongs_to :grado
  belongs_to :horario
  belongs_to :instructor
  
  # este coeficiente expresa perfil o no, alumno, exalumno, etc. se copia a la visita.
  belongs_to :coeficiente
  
  #-----------------------------------------------------------------------------
  # VALIDACIONES
  
  before_validation :strip_fields
  
  validates_length_of [:dni,:nombres,:apellidos,:tel,:cel,:mail], :maximum => 45
  validates_length_of :dire, :maximum => 100  

  validates_presence_of :coeficiente, :message=> "^Falta indicar el coeficiente de esta persona."
  validates_presence_of :nombres, :message=> "no puede estar vacio."
  validates_presence_of :genero, :message=> "no puede estar vacio."

  validates_uniqueness_of :dni, :scope=>[:dni,:nombres, :apellidos], :allow_nil=>true, :message=>'^Esta persona YA ESTA REGISTRADA. Si se trata de una nueva persona con el mismo nombre especifique su DNI.'

  # VALID_MAIL_REGEX esta definido en enviroment.rb
  validates_format_of :mail, :with => VALID_MAIL_REGEX, :message=>"no valido.", :if=>:mail_not_empty

  validates_format_of :cel, :with => TEL_REGEX, :message=>"no valido. Caracteres permitidos:' ', '.' y '-'", :if=>:cel_not_empty
  validates_format_of :tel, :with => TEL_REGEX, :message=>"no valido. Caracteres permitidos:' ', '.' y '-'", :if=>:tel_not_empty

  validates_inclusion_of :genero, :in => %w(m h)

  def tel_not_empty
    return (tel and (tel != ''))
  end
  
  def cel_not_empty
    return (cel and (cel != ''))  
  end
  
  def mail_not_empty
    return (mail and (mail != ''))
  end

  # ----------------------------------------------------------------------------
  # DEFINICIONES

  # retorna la edad de la persona
  def age
    ydiff = Date.today.year - fecha_nacimiento.year
    if fecha_nacimiento.month > Date.today.month or (fecha_nacimiento.month == Date.today.month and fecha_nacimiento.day > Date.today.day) then
      return ydiff-1
    else
      return ydiff
    end
  end

  # devuelve el nombre completo de la persona
  def nombre_completo
    return "#{nombres} #{apellidos}"
  end

  # TODO ahora retorna el coeficiente para actualizarlo afuera xq no logro que modifique el valor.
  # actualiza el coeficiente_id para que sea coherente con las matriculas, evasiones y visitas registradas
  def actualizar_coeficiente
    eva = evasions.find(:first,:order=>'fecha DESC', :conditions=>'fecha<=CURDATE()')
    mat = matriculas.find(:first,:order=>'fecha DESC', :conditions=>'fecha<=CURDATE()')
    vis = visitas.find(:first, :order=>'fecha DESC', :conditions=>'fecha<=NOW()')
    
    if eva.nil? and mat.nil? then
      if vis.nil? then
        # si no tiene evasiones ni matriculas ni visitas no realizo cambios
      else
        # si tiene visitas le dejo el coeficiente de su ultima visita
        coeficiente_id = vis.coeficiente_id
      end
    elsif eva.nil? then # tiene matricula pero no tiene ninguna evasion, es alumno
      coeficiente_id = Coeficiente::ALUMNO
    elsif mat.nil? then # tiene evasion pero no tiene ninguna matricula, es exalumno
      coeficiente_id = Coeficiente::EXALUMNO
    elsif eva.fecha < mat. fecha 
      coeficiente_id = Coeficiente::ALUMNO
    elsif eva.fecha == mat.fecha
      coeficiente_id = (es_alumno?)? Coeficiente::EXALUMNO : Coeficiente::ALUMNO
    else
      coeficiente_id = Coeficiente::EXALUMNO
    end
    save!
    return coeficiente_id
  end

  # devuelve verdadero si la persona es alumno, false si no lo es.
  def es_alumno?
    return coeficiente_id == Coeficiente::ALUMNO
  end  

  # devuelve verdadero si se trata de una VISITA P-, P o P+
  # ATENCION: para esta funcion alumnos y exalumnos devuelven falso
  def es_prospect?
    return ((coeficiente_id > Coeficiente::FP) and (coeficiente_id < Coeficiente::ALUMNO))
  end

  #devuelve verdadero si el alumno tiene un plan vip vigente
  def es_vip?
    p = plans.find(:first, :conditions=>'ini<= CURDATE() AND fin>=CURDATE()', :order=>'fin DESC')
    return ((p != nil) and p.vip)
  end
  
  #devuelve la fecha de fin de plan mas lejana, es decir del ultimo plan.
  #devuelve nulo si no hay planes
  def fin_plan
    aux = plans.find(:first,:order=>'fin DESC')
    return aux.fin if aux
  end

  # devuelve true si la persona tiene un plan vigente
  # devuelve false si no tiene plan vigente, o no es alumno
  def plan_vigente?
    return ((coeficiente_id==Coeficiente::ALUMNO) and (plans.count(:conditions=>'ini<=CURDATE() AND fin>=CURDATE()') > 0))
  end

  # devuelve el plan vigente. si tiene mas de uno devuelve el que comienza primero.
  def plan_vigente
    return plans.find(:first, :conditions=>'ini<=CURDATE() AND fin>=CURDATE()', :order=>'ini ASC')
  end
  
  # Devuelve la FECHA de la ultima gestion o nil
  def ultima_gestion
    aux = gestions.find(:first,:order=>'fecha DESC')
    return aux.fecha if aux
  end

  # Devuelve la FECHA de la ultima reunion o nil
  def ultima_reunion
    aux = reunions.find(:first,:order=>'fecha DESC')
    return aux.fecha if aux
  end
  
  # Devuelve la FECHA de la ultima revisacion concretada o nil
  def ultima_revisacion
    aux = revisacions.find_done(:first,:order=>'fecha DESC')
    return aux.fecha if aux
  end
  
  # Devuelve la FECHA de la ultima matricula o nil
  def ultima_matricula
    aux = matriculas.find(:first,:order=>'fecha DESC')
    return aux.fecha if aux
  end
  
  # Devuelve la FECHA de la ultima evasion o nil
  def ultima_evasion
    aux = evasions.find(:first,:order=>'fecha DESC')
    return aux.fecha if aux
  end

  # Devuelve la FECHA de la ultima visita o nil
  def ultima_visita
    aux = visitas.find(:first,:order=>'fecha DESC')
    return aux.fecha if aux
  end
  
  #devuelve verdadero si es alumno de yoga
  def alumno_de_yoga
    return (coeficiente_id==Coeficiente::ALUMNO and grado>Grado::ASPIRANTE)
  end
  
  #devuelve verdadero si es alumno de preyoga
  def alumno_de_preyoga
    # podria chequear si el alumno es vip o no.
    return (coeficiente_id==Coeficiente::ALUMNO and grado==Grado::ASPIRANTE)
  end

  def self.nro_alumnos
    Persona.count_alumnos
    # quito la variable para ver si eso hace que se refresque la info. por alguna razon en el servidor necesito
    # reiniciar el dispatch para que se refresque la informacion.
#    @nro_alumnos ||= Persona.count_alumnos
  end  

  def self.nro_alumnos_yoga
    @nro_alumnos_yoga ||= Persona.count_alumnos_yoga
  end  
  
  def self.nro_alumnos_preyoga
    @nro_alumnos_preyoga ||= Persona.count_alumnos_preyoga
  end  

  # devuelve el numero de alumno a determianda fecha
  def self.nro_alumnos_al(date)
    return Persona.count(:all, :conditions=>alumnos_al_query(date))
  end
  
  # devuleve el listado de alumnos a determinada fecha
  # es identico a nro_alumnos_al pero utiliza find en lugar de count.
  def self.alumnos_al(date)
    return Persona.find(:all, :conditions=>alumnos_al_query(date))
  end
  
  private
  
  def strip_fields
    nombres = nombres.strip if nombres
    apellidos = apellidos.strip if apellidos
    mail = mail.strip if mail
  end
  
  # genero el script de condiciones sql para encontrar alumnos en determinada fecha
  def self.alumnos_al_query(date)
    # personas que se matricularon antes de la fecha y no tienen evasion posterior a la matricula y posterior a la fecha.
    alumnos_correctos = "EXISTS(
                              SELECT * FROM matriculas m WHERE m.persona_id = personas.id AND DATEDIFF(m.fecha,'#{date.strftime(MYSQL_DATE)}')<=0 AND
                                                           NOT EXISTS (
                              SELECT * FROM evasions e WHERE e.persona_id=personas.id AND DATEDIFF(e.fecha,m.fecha)>=0 AND DATEDIFF(e.fecha,'#{date.strftime(MYSQL_DATE)}')<=0)
                                                                )"

    # personas que fueron ingresadas directamente como alumnos al sistema y siguen siendolo
    alumnos_cableados = "coeficiente_id=#{Coeficiente::ALUMNO} AND NOT EXISTS(SELECT * FROM matriculas m WHERE m.persona_id = personas.id)"

    # personas que fueron ingresadas directamente como alumnos al sistema pero ya son exalumnos
    exalumnos_cableados_entonces = "NOT EXISTS(SELECT * FROM matriculas m WHERE m.persona_id = personas.id AND DATEDIFF(m.fecha,'#{date.strftime(MYSQL_DATE)}')<=0)
        AND
                    EXISTS(SELECT * FROM evasions e WHERE e.persona_id=personas.id AND DATEDIFF(e.fecha,'#{date.strftime(MYSQL_DATE)}')>=0)"
    return "(#{alumnos_correctos}) OR (#{alumnos_cableados}) OR (#{exalumnos_cableados_entonces})"
  end
 end
